Before your application attempts to make a network connection, you
need to know whether you have a network available, and depending on what
you want to do you might also want to know whether the device is connected
to a WiFi or cellular network.
Warning:
One of the more common reasons for Apple to reject an application
submitted for review is that the application doesn’t correctly notify
the user when the application fails to access the network. Apple
requires that you detect the state of the network connection and report
it to the user when the connection is unavailable, or otherwise handle
it in a graceful manner.
1. Apple’s Reachability Class
Helpfully, Apple has provided some sample code to deal with
detecting current network status. The Reachability code is available at http://developer.apple.com/iphone/library/samplecode/Reachability/.
Warning:
Two different versions of the Apple Reachability code are in
general circulation. The earlier version, which appears in many web
tutorials and has been widely distributed, dates from the pre-2.0 SDK.
The newer version, released in August 2009, is much improved and
supports asynchronous connection monitoring. However, the interface
offered by the two versions is very different, so to avoid confusion
you need to be aware which version of the Reachability code you’re
using.
Download the Reachability.zip file from
Apple, and unzip it. Open the Reachability/Classes
directory and grab the Reachability.h and
Reachability.m files from the Xcode project and
copy them onto your Desktop (or any convenient location). This is the
Reachability class that we want to
reuse in our projects.
To use the Reachability class
in a project, you must do the following after you create the project in
Xcode:
Drag and drop both the header and implementation files into
the Classes group in your project, and be sure to tick the “Copy
items into destination group’s folder (if needed)” checkbox in the
pop-up dialog that appears when you drop the files into
Xcode.
Right-click or Ctrl-click on the Frameworks group, select
Add→Existing Frameworks, and then
select SystemConfiguration.framework in
the Frameworks selector pop up, as shown in Figure 1. The
Reachability code needs this framework and it has to be added to
your projects where you use it.
There are two ways to make use of Apple’s Reachability code:
synchronously or asynchronously.
1.1. Synchronous reachability
The synchronous case is the simpler of the two approaches;
here we import the Reachability.h
header file into our code and then carry out a “spot-check” as to
whether the network is reachable, and whether we have a wireless or
WWAN connection:
#import "Reachability.h"
... some code omitted ...
Reachability *reach = [[Reachability reachabilityForInternetConnection] retain];
NetworkStatus status = [reach currentReachabilityStatus];
or alternatively, whether a specific host is reachable:
Reachability *reach =
[[Reachability reachabilityWithHostName: @"www.apple.com"] retain];
NetworkStatus status = [reach currentReachabilityStatus];
We can then use a simple switch statement to decode the network
status. The following code turns the status flag into an NSString, perhaps to update a UILabel in the application interface, but of
course you can trigger any action you need to (disabling parts of your
user interface, perhaps?) depending on the current network
status:
- (NSString *)stringFromStatus:(NetworkStatus ) status {
NSString *string;
switch(status) {
case NotReachable:
string = @"Not Reachable";
break;
case ReachableViaWiFi:
string = @"Reachable via WiFi";
break;
case ReachableViaWWAN:
string = @"Reachable via WWAN";
break;
default:
string = @"Unknown";
break;
}
return string;
}
We can easily put together a quick application to illustrate use
of the Reachability code. Open Xcode and start a new project. Choose a
view-based iPhone OS application, and when prompted, name it
“NetworkMonitor”. Import the Reachability code, add the
SystemConfiguration.framework into your new
project (as discussed in the preceding section), open the
NetworkMonitorAppDelegate.h interface file in the
Xcode editor, and declare the stringFromStatus: method as shown in the
following code:
#import <UIKit/UIKit.h>
#import "Reachability.h"
@class NetworkMonitorViewController;
@interface NetworkMonitorAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
NetworkMonitorViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet
NetworkMonitorViewController *viewController;
- (NSString *)stringFromStatus:(NetworkStatus )status;
@end
Save your changes, and open the
NetworkMonitorAppDelegate.m implementation file in the
Xcode editor and modify the applicationDidFinishLaunching:
method:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
Reachability *reach =[[Reachability reachabilityForInternetConnection] retain];
NetworkStatus status = [reach currentReachabilityStatus];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Reachability"
message:[self stringFromStatus: status]
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
The final step is to add the stringWithStatus: method I showed earlier to
NetworkMonitorAppDelegate.m. Save your changes
and click the Build and Run button on the Xcode toolbar to compile
your code and deploy it into iPhone Simulator. You should see
something similar to Figure 2.
1.2. Asynchronous reachability
The asynchronous approach is (only slightly) more
complicated, but using the Reachability class in this way means your
application can be notified of changes in the current network status.
You must first import the Reachability.h header
file into your code. After that, you need to register the class that
must monitor the network as an observer for the kReachabilityChangedNotification
event:
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(reachabilityChanged:)
name: kReachabilityChangedNotification
object: nil];
Then you need to create a Reachability instance and start event
notification:
Reachability *reach =
[[Reachability reachabilityWithHostName: @"www.apple.com"] retain];
[reach startNotifer];
When the network reachability status changes, the Reachability instance will notify your code
by calling the reachabilityChanged:
method. What you do in that method of course very much depends
on why you’re monitoring the network status in
the first place; however, the stub of such a method would look like
this:
- (void) reachabilityChanged: (NSNotification *)notification {
Reachability *reach = [notification object];
if( [reach isKindOfClass: [Reachability class]]) {
NetworkStatus status = [reach currentReachabilityStatus];
// Insert your code here
}
}
1.3. Using Reachability directly
The Apple Reachability class
is just a friendly wrapper around the SCNetworkReachability
programming interface, which is part of
SystemConfiguration.framework. While I recommend
using Apple’s sample code if possible, you can use the interfaces
directly if you need to do something out of the ordinary.